package com.gss.armory.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.webflow.execution.RequestContext;

import com.gss.armory.domain.DocAttDTO;
import com.gss.armory.domain.DocGeneralDetailsDTO;
import com.gss.armory.domain.DocGeneralDetailsDTO.DocumentFlowStatus;
import com.gss.armory.domain.CompanyDetailsDTO;
import com.gss.armory.domain.DocReviewerApproverForWFDTO;
import com.gss.armory.domain.DocumentAuthSignatoryDTO;
import com.gss.armory.domain.DocumentCustodianDetailsDTO;
import com.gss.armory.domain.DocumentLinkDTO.DocLinkType;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowEventStatus;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowStatus;
import com.gss.armory.domain.UserActivityGroup;
import com.gss.armory.domain.UserActivityGroup.DocActivityType;
import com.gss.armory.form.DocumentCustodianDetailsForm;
import com.gss.armory.form.UserActivityForm;
import com.gss.armory.form.UserSearchForm;
import com.gss.armory.persistence.CommonDAO;
import com.gss.armory.persistence.DocumentDAO;
import com.gss.armory.persistence.WorkFlowDAO;
import com.gss.common.service.MailService;
import com.gss.common.util.ApplicationConstants;
import com.gss.common.util.ApplicationMaps;
import com.gss.common.util.ApplicationUtilities;
import com.gss.security.domain.RoleDetailsDTO;
import com.gss.security.domain.SaveDataInWFTable;
import com.gss.security.domain.SuperficialRolesMapping;
import com.gss.security.domain.UserDetailsDTO;

@Service
public class WorkFlowService {
	
	private Logger logger = Logger.getLogger(WorkFlowService.class);
	
	
	@Autowired
	WorkFlowDAO workflowDao;
	
	@Autowired
	DocumentDAO documentDAO;
	
	@Autowired
	ProcessDocumentService processDocumentService;
	
	@Autowired
	MailService mailService;
	
	@Autowired
	CommonDAO commonDAO;
	
	public List<DocumentWorkflowDetailsDTO> workFlowList(RequestContext requestContext){
		logger.debug("inside method workFlowList of to list of all details: ");
		List<DocGeneralDetailsDTO> workflowList = new ArrayList<DocGeneralDetailsDTO>();
		List<DocumentWorkflowDetailsDTO> workflowList2 = null;
		HashMap<Integer, String> docTypeMap = new HashMap<Integer, String>();
		Set<Enum> docStatusSet = new HashSet<Enum>();
		Set<Enum> wfStatusSet = new HashSet<Enum>();
		try {
			workflowList2 = workflowDao.getWorkFlowDetails();
			for(DocumentWorkflowDetailsDTO detailsDTO : workflowList2){
				wfStatusSet.add(detailsDTO.getWfStatus());
			}
//			DetachedCriteria criteria = null;
			for (DocumentWorkflowDetailsDTO documentWorkflowDetailsDTO : workflowList2) {
				documentWorkflowDetailsDTO.setStrCreatedAuthor(ApplicationMaps.USERID_USERNAME_MAP.get(documentWorkflowDetailsDTO.getStrCreatedAuthor()));
				DetachedCriteria criteria = DetachedCriteria.forClass(DocGeneralDetailsDTO.class);
				criteria.add(Restrictions.eq("docId", documentWorkflowDetailsDTO.getDocId()));
				workflowList.addAll(documentDAO.getDocumentDetails(criteria));
				for(DocGeneralDetailsDTO dto : workflowList){
					docTypeMap.put(dto.getDocTypeId(), dto.getDocType());
					docStatusSet.add(dto.getDocumentStatus());
				}
			}	
		} 
		catch(DataAccessException accessException) {
			logger.error(accessException.getMessage(),accessException);
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		HashMap<Enum, String> wfStatusMap = new HashMap<Enum, String>();
		for (Enum wfStatus : wfStatusSet) {
			wfStatusMap.put(wfStatus, ApplicationMaps.STATUS_NAME_MAP.get(wfStatus));
		}
		requestContext.getFlowScope().put("docTypeMap", docTypeMap);
		requestContext.getFlowScope().put("docStatusSet", docStatusSet);
		requestContext.getFlowScope().put("wfStatusMap", wfStatusMap);
		
		requestContext.getFlowScope().put("docGeneralDetailsList", workflowList);
		requestContext.getFlowScope().put("unfilteredList", workflowList);
		requestContext.getFlowScope().put("unfilteredWorkflowList",workflowList2);
		
		requestContext.getFlowScope().put("companyList", ApplicationMaps.getCompaniesMappedToUser());
		return workflowList2;
	}
	
	public List<DocumentWorkflowDetailsDTO> copyWorkFlowList(RequestContext requestContext, int docType){
		logger.debug("inside method workFlowList of to list of all details: for document with docTypeId: " + docType);
		List<DocGeneralDetailsDTO> workflowList = new ArrayList<DocGeneralDetailsDTO>();
		List<DocumentWorkflowDetailsDTO> workflowList2 = null;
		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentWorkflowDetailsDTO.class);
		try {
			/*String strdocType = requestContext.getRequestScope().getString("docType");
			int docType = Integer.parseInt(strdocType);*/
			String docStatus = requestContext.getRequestParameters().get("docStatus");
			String wfStatus = requestContext.getRequestParameters().get("docWfStatus");
			long locId = requestContext.getRequestParameters().getLong("businessUnit");
			int compId = requestContext.getRequestParameters().getInteger("company");
			
			if(null != wfStatus && !ApplicationConstants.ALL_STRING.equalsIgnoreCase(wfStatus)) {
				criteria.add(Restrictions.eq("wfAssignedUser", ApplicationUtilities.getCurrentUser()));
				criteria.add(Restrictions.eq("wfEventStatus", WorkflowEventStatus.OPEN));
				criteria.add(Restrictions.eq("wfStatus", WorkflowStatus.valueOf(wfStatus)));
				workflowList2 = workflowDao.copyGetWorkFlowDetails(criteria);
			}
			else {
				criteria.add(Restrictions.eq("wfAssignedUser", ApplicationUtilities.getCurrentUser()));
				criteria.add(Restrictions.eq("wfEventStatus", WorkflowEventStatus.OPEN));
				workflowList2 = workflowDao.copyGetWorkFlowDetails(criteria);
			}
	
			List<DocumentWorkflowDetailsDTO> listToRemove = new ArrayList<DocumentWorkflowDetailsDTO>();
			List<DocGeneralDetailsDTO> listToTraverse = new ArrayList<DocGeneralDetailsDTO>();
 			
			DetachedCriteria criteria2 = null;
			for (DocumentWorkflowDetailsDTO documentWorkflowDetailsDTO : workflowList2) {
				documentWorkflowDetailsDTO.setStrCreatedAuthor(ApplicationMaps.USERID_USERNAME_MAP
						.get(documentWorkflowDetailsDTO.getStrCreatedAuthor()));
				criteria2 = DetachedCriteria.forClass(DocGeneralDetailsDTO.class);
				
				criteria2.add(Restrictions.eq("docId", documentWorkflowDetailsDTO.getDocId()));
				
				if(!(ApplicationConstants.ALL_INT == docType)){
					criteria2.add(Restrictions.eq("docTypeId", docType));
				}
				if(null != docStatus && !ApplicationConstants.ALL_STRING.equalsIgnoreCase(docStatus)){
					criteria2.add(Restrictions.eq("documentStatus", DocumentFlowStatus.valueOf(docStatus)));
				}
				if(ApplicationConstants.ALL_LONG != locId) {
					criteria2.add(Restrictions.eq("docLocId", locId));
				}
				if(ApplicationConstants.ALL_INT.intValue() != compId) {
					criteria2.add(Restrictions.eq("docCompanyId", compId));
				}
				
				listToTraverse = documentDAO.getDocumentDetails(criteria2);
				
				if(listToTraverse.size() > 0){
					workflowList.addAll(listToTraverse);
				}
				else{
					listToRemove.add(documentWorkflowDetailsDTO);
				}
			}
			if(listToRemove.size() != 0){
				workflowList2.removeAll(listToRemove);
			}
			
			requestContext.getFlowScope().put("docType", docType);
			requestContext.getFlowScope().put("docStatus", docStatus);
			requestContext.getFlowScope().put("docWfStatus", wfStatus);
			requestContext.getFlowScope().put("company", compId);
			requestContext.getFlowScope().put("businessUnit", locId);
			
		}
		catch (Throwable e) {
			logger.error(e.getMessage(), e);
		}
		
		requestContext.getFlowScope().put("docGeneralDetailsList", workflowList);
		
		
		return workflowList2;
	}

	public List<DocAttDTO> docDetailList(long docId){
		logger.debug("inside method(docDetailList): for document with docId: "+docId);
		List<DocAttDTO> docDetail = null;
		try 
		{
			//workflowList=workflowDao.getWorkFlowDetails();
			docDetail=workflowDao.getDocDetail(docId);
		} 
		catch(DataAccessException accessException){
			logger.error(accessException.getMessage(),accessException);
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		return docDetail;
	}

	
	public void update(RequestContext requestContext){
		long docId=requestContext.getRequestParameters().getLong("docId");
		logger.debug("inside method(update): updating for document with docId: " + docId);
		DocGeneralDetailsDTO  docGeneralDetailsDTO = new DocGeneralDetailsDTO();
		docGeneralDetailsDTO.setDocId(docId);
		try {
			workflowDao.loadDocGeneralDetals(docGeneralDetailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		String masterCode = docGeneralDetailsDTO.getDocTypeId()+"#"+docGeneralDetailsDTO.getDocLocId()+"#"+docGeneralDetailsDTO.getDocDepttId();
		if(ApplicationMaps.ARMORY_REVIEVER_APPROVER.containsKey(masterCode)){
			DocumentWorkflowDetailsDTO detailsDTO = new DocumentWorkflowDetailsDTO();		
	  		String remarks=requestContext.getRequestParameters().get("remarks");
	  		long wfId = requestContext.getRequestParameters().getLong("currentWfId");
			detailsDTO.setWfId(wfId);
			logger.debug("current workflowId: " + wfId);
			try {
				workflowDao.loadWorkflowDetails(detailsDTO);
			} catch (Exception e1) {
				logger.error(e1.getMessage(),e1);
			}
			
			if(detailsDTO.getWfEventStatus().equals(WorkflowEventStatus.CLOSED)){
				requestContext.getFlowScope().put("statusMsg", "This action item is already closed. Please refresh your task list.");
				return;
			}
			requestContext.getFlowScope().put("statusMsg", "Document Submitted Successfully");
			detailsDTO.setRemarks(remarks);
			try 
			{    
				if(workflowDao.updateDocStatus(detailsDTO,new DocGeneralDetailsDTO())){
			    	if(!detailsDTO.getWfStatus().equals(WorkflowStatus.PFA)){
			    		DocumentWorkflowDetailsDTO newWorkflowAction = workflowDao.createWfRowForSubmit(detailsDTO);
			    		mailService.sendMailNotification( new String[]{ ApplicationMaps.USERID_EMAIL_MAP.get(newWorkflowAction.getWfAssignedUser())},
			    				new String[]{ApplicationMaps.USERID_EMAIL_MAP.get(ApplicationUtilities.getCurrentUser())},
			    				getMessageForNotificationMail(newWorkflowAction, docGeneralDetailsDTO),
			    				"DMS Workflow - New Action Item Notification");
					}	
				}
			}
			catch(DataAccessException accessException){
				logger.error(accessException.getMessage(),accessException);
			}
			catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		}
		else
			requestContext.getFlowScope().put("statusMsg", "Reviewer / Approver mapping missing. Please contact administrator.");
	}
	
	
	
	public void saveCustodianDetails(RequestContext requestContext,DocumentCustodianDetailsForm custodianDeatailsForm) {
		
		DocumentWorkflowDetailsDTO detailsDTO = new DocumentWorkflowDetailsDTO();		
  		long wfId = requestContext.getRequestParameters().getLong("currentWfId");
		detailsDTO.setWfId(wfId);
		long docId=requestContext.getRequestParameters().getLong("docId");
		logger.debug("inside method(saveCustodianDetails): saving custodian details with cuastodianId: " 
				+ custodianDeatailsForm.getCustodianId() + " for document with docId: " + docId);
		custodianDeatailsForm.setDocId(docId);
		DocumentCustodianDetailsDTO custodianDetailsDTO = ApplicationUtilities.getVaultDetalsFromDetailsForm(custodianDeatailsForm);
		try {
			workflowDao.saveVaultDetails(custodianDetailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		custodianDeatailsForm.setVaultId(custodianDetailsDTO.getVaultId());
		requestContext.getFlowScope().put("documentCustodianDetailsForm", custodianDeatailsForm);
	}
	
	public void updateCustodianDetails(RequestContext requestContext,DocumentCustodianDetailsForm custodianDeatailsForm) {
		
		long docId=requestContext.getRequestParameters().getLong("docId");
		logger.debug("inside method(updateCustodianDetails): updating custodian details for document with docId: " + docId);
		custodianDeatailsForm.setDocId(docId);
		DocumentCustodianDetailsDTO custodianDetailsDTO = ApplicationUtilities.getVaultDetalsFromDetailsForm(custodianDeatailsForm);
		try {
			workflowDao.saveVaultDetails(custodianDetailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		custodianDeatailsForm.setVaultId(custodianDetailsDTO.getVaultId());
		requestContext.getFlowScope().put("documentCustodianDetailsForm", custodianDeatailsForm);
	}
	
	public void approve(RequestContext requestContext){
		DocumentWorkflowDetailsDTO detailsDTO = new DocumentWorkflowDetailsDTO();		
  		String remarks=requestContext.getRequestParameters().get("remarks");
  		long wfId = requestContext.getRequestParameters().getLong("currentWfId");
		detailsDTO.setWfId(wfId);
		long docId=requestContext.getRequestParameters().getLong("docId");
		logger.debug("inside method(approve): for document with docId: " + docId + " and workflowId: " + wfId);
//		custodianDeatailsForm.setDocId(docId);
//		DocumentCustodianDetailsDTO custodianDetailsDTO = ApplicationUtilities.getVaultDetalsFromDetailsForm(custodianDeatailsForm);
		try {
			workflowDao.loadWorkflowDetails(detailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		if(detailsDTO.getWfEventStatus().equals(WorkflowEventStatus.CLOSED)){
			requestContext.getFlowScope().put("statusMsg","This action item is already closed. Please reload your task list.");
		}
		DocGeneralDetailsDTO generalDetailsDTO = new DocGeneralDetailsDTO();
		generalDetailsDTO.setDocId(docId);
		try {
			workflowDao.loadDocGeneralDetals(generalDetailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		long docIdToBeRenewed = 0;
		if(generalDetailsDTO.getDocumentStatus().equals(DocumentFlowStatus.RenewWfip)){
			try {
				docIdToBeRenewed =	Long.parseLong(generalDetailsDTO.getDocCode());
			}catch (NumberFormatException e) {
				logger.error(e.getMessage(),e);
			} 
			catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		}
		
		generalDetailsDTO.setDocCode(ApplicationUtilities.generateDocumentCode(generalDetailsDTO));
		detailsDTO.setRemarks(remarks);
		try 
		{    DocumentFlowStatus documentFlowStatus = generalDetailsDTO.getDocumentStatus();
			if(workflowDao.updateDocStatus(detailsDTO,generalDetailsDTO)) {
		    	if(!detailsDTO.getWfStatus().equals(WorkflowStatus.PFA)) {
		    		workflowDao.createWfRowForSubmit(detailsDTO);			
				}else if(generalDetailsDTO.isRenewable()) {
					workflowDao.createWFRowForRenewableDocument(detailsDTO, generalDetailsDTO);
				}
		    	
		    	// extra steps to be performed in case a renewed document is getting approved
		    	if(detailsDTO.getWfStatus().equals(WorkflowStatus.PFA) && documentFlowStatus.equals(DocumentFlowStatus.RenewWfip) && docIdToBeRenewed != 0){
		    		logger.debug("Renewed doc is getting approved. Copy link details");
		    		processDocumentService.copyDocumentLinksFromExpiredToRenewedDoc(docIdToBeRenewed, docId, true,DocLinkType.Renewal);
		    		processDocumentService.updateDocStatus(docIdToBeRenewed, DocumentFlowStatus.Expired);
		    	}
		    	
		    	
		    	mailService.sendMailNotification( getUserListToInformOnApproval(requestContext, generalDetailsDTO, detailsDTO), null,
	    				getMessageForNotificationMail(detailsDTO, generalDetailsDTO), "DMS Workflow - New Document added to archive");
			}
			
			requestContext.getFlowScope().put("statusMsg", "Document Published With DocCode " +generalDetailsDTO.getDocCode()+ " Approved by " + ApplicationMaps.USERID_USERNAME_MAP.get(ApplicationUtilities.getCurrentUser()));

		}
		catch(DataAccessException accessException)
		{
			logger.error(accessException.getMessage(), accessException);
		}
		catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	private String[] getUserListToInformOnApproval(RequestContext context, DocGeneralDetailsDTO docGeneralDetailsDTO,DocumentWorkflowDetailsDTO workflowDetailsDTO){
		logger.debug("inside method(getUserListToInformOnApproval)");
		Set<String> userEmailList = new HashSet<String>();
		//uploader
		if(!ApplicationUtilities.checkIfNullOrBlank(docGeneralDetailsDTO.getStrCreatedAuthor()))
			userEmailList.add(ApplicationMaps.USERID_EMAIL_MAP.get(docGeneralDetailsDTO.getStrCreatedAuthor()));
		//reviewer
		if(!ApplicationUtilities.checkIfNullOrBlank(workflowDetailsDTO.getStrCreatedAuthor()))
			userEmailList.add(ApplicationMaps.USERID_EMAIL_MAP.get(workflowDetailsDTO.getStrCreatedAuthor()));
		//approver
		userEmailList.add(ApplicationUtilities.getCurrentUserEmail());
		
		Map<String,String> userPrintGroupMap = (Map<String, String>) context.getFlowScope().get("viewMap");
		Map<String,String> userViewGroupMap = (Map<String, String>) context.getFlowScope().get("printMap");
		
		if(null != userPrintGroupMap){
			for(String username : userPrintGroupMap.keySet())
				userEmailList.add(ApplicationMaps.USERID_EMAIL_MAP.get(username));
		}
		if(null != userViewGroupMap){
			for(String username : userViewGroupMap.keySet())
				userEmailList.add(ApplicationMaps.USERID_EMAIL_MAP.get(username));
		}

		logger.debug("Email list for approval: " + userEmailList);
		
		String[] emailArray = new String[userEmailList.size()];
		int counter=0;
		for(String email : userEmailList){
			emailArray[counter] = email;
			counter++;
		}
		
		return emailArray;
	}
	
	public void reject(RequestContext requestContext){
		
		DocumentWorkflowDetailsDTO detailsDTO = new DocumentWorkflowDetailsDTO();
  		long wfId = Long.parseLong(requestContext.getRequestParameters().get("currentWfId"));
  		long docId=requestContext.getRequestParameters().getLong("docId");
  		logger.debug("inside method(reject): fordocument with docId: " + docId);
  		
  		String remarks=requestContext.getRequestParameters().get("remarks");
  		DocGeneralDetailsDTO  docGeneralDetailsDTO = new DocGeneralDetailsDTO();
		docGeneralDetailsDTO.setDocId(docId);
		try {
			workflowDao.loadDocGeneralDetals(docGeneralDetailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		detailsDTO.setWfId(wfId);
		try {
			workflowDao.loadWorkflowDetails(detailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		detailsDTO.setRemarks(remarks);
		detailsDTO.setVersion(detailsDTO.getVersion() + 1);
		detailsDTO.setUpdatedDate(new Date());
		detailsDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
		requestContext.getFlowScope().put("statusMsg", "Document Rejected");
		try 
		{    
			if(workflowDao.updateWfEventStatus(detailsDTO))
			{
				DocumentWorkflowDetailsDTO newWorkflowAction = workflowDao.createWfRowForReject(detailsDTO);
				mailService.sendMailNotification( new String[]{ ApplicationMaps.USERID_EMAIL_MAP.get(newWorkflowAction.getWfAssignedUser())},
	    				new String[]{ApplicationMaps.USERID_EMAIL_MAP.get(ApplicationUtilities.getCurrentUser())},
	    				getMessageForNotificationMail(newWorkflowAction, docGeneralDetailsDTO),
	    				"DMS Workflow - New Action Item Notification");
			}
		} 
		catch(DataAccessException accessException)
		{
			logger.error(accessException.getMessage(),accessException);
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		
	}
	public void getDefaultUsers(RequestContext requestContext)
	{
		Long docId = requestContext.getRequestParameters().getLong("docId");
		logger.debug("Inside Method (getDefaultUsers): for document with docId: " + docId);
		
		DocGeneralDetailsDTO detailsDTO = new DocGeneralDetailsDTO();
		detailsDTO.setDocId(docId);
		try {
			workflowDao.loadDocGeneralDetals(detailsDTO);
		} catch (Exception e1) {
			logger.error(e1.getMessage(),e1);
		}
		
		//check if document renewal has come for approval - if yes copy user activity mapping from oldDoc to New and delete for old
		if(detailsDTO.getDocumentStatus().equals(DocumentFlowStatus.RenewWfip)){
			long docIdToBeRenewed = 0l;
			try {
				docIdToBeRenewed =	Long.parseLong(detailsDTO.getDocCode());
			} catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
			if(docIdToBeRenewed != 0){
				processDocumentService.copyUserActivityDetails(docIdToBeRenewed, docId, true);
			}
		}
		/**/
		
		//Get document related users i.e. reviewer, approver, uploader
		List<UserDetailsDTO> userDetailsDTOs = new ArrayList<UserDetailsDTO>();
		List<String> usersList = new ArrayList<String>();
		
		//getting doc details on basis of docid for getting uploader
		DetachedCriteria docGeneralCriteria = DetachedCriteria.forClass(DocGeneralDetailsDTO.class);
		docGeneralCriteria.add(Restrictions.eq("docId", docId));
		List<DocGeneralDetailsDTO> documentGeneralList = commonDAO.loadAllByCriteria(docGeneralCriteria);
		
		//Creating master code for reviewer and approver
		DocGeneralDetailsDTO documentObject = documentGeneralList.get(0);
		String masterCode = documentObject.getDocTypeId() + "#" + documentObject.getDocLocId() + "#" + documentObject.getDocDepttId();
		//fetching reviewer and approver acc to master code for document
		DetachedCriteria docRevApprCriteria = DetachedCriteria.forClass(DocReviewerApproverForWFDTO.class);
		docRevApprCriteria.add(Restrictions.eq("masterCode", masterCode));
		
		List<DocReviewerApproverForWFDTO> reviewerApproverList = commonDAO.loadAllByCriteria(docRevApprCriteria);
		DocReviewerApproverForWFDTO reviewerApprover = reviewerApproverList.get(0);
		
		String reviewerId = reviewerApprover.getReviewer();			//reviewer User Id
		String approverId = reviewerApprover.getApprover();			//approver User Id
		String uploaderId = documentObject.getStrCreatedAuthor(); 	//uploader User Id
		
		//adding all the users to a list names 'usersList'
		usersList.add(reviewerId);
		usersList.add(approverId);
		usersList.add(uploaderId);
		
		//checking the company of document is group company or stand-alone company
		List<UserDetailsDTO> userList = null;
		Set<UserDetailsDTO> superficialUsers = new HashSet<UserDetailsDTO>();
		
		CompanyDetailsDTO companyDetailsDTO = ApplicationMaps.COMPANYID_COMPANY_MAP.get(documentObject.getDocCompanyId());
		if(ApplicationConstants.SUBSIDIARY_COMPANY.equalsIgnoreCase(companyDetailsDTO.getCompanyType())) {
			int parentCompanyId = companyDetailsDTO.getParentId();
			DetachedCriteria userCompanyCriteria = DetachedCriteria.forClass(UserDetailsDTO.class);
			userCompanyCriteria.add(Restrictions.eq("cdId", parentCompanyId));
			userList = commonDAO.loadAllByCriteria(userCompanyCriteria);
		}
		//fetching a set of superficial users for the company of document only having role Owner and CCC
		if(null != userList){
			for (UserDetailsDTO user : userList) {
				Collection<GrantedAuthority> rolesList = user.getAuthorities();
				for (GrantedAuthority grantedAuthority : rolesList) {
					RoleDetailsDTO roleDetailsDTO = (RoleDetailsDTO) grantedAuthority;
					if(roleDetailsDTO.getRoleId().equalsIgnoreCase(ApplicationConstants.ROLE_OWNER)
							|| roleDetailsDTO.getRoleId().equalsIgnoreCase(ApplicationConstants.ROLE_CHIEF_CENTRAL_CONTROLLER)){
						superficialUsers.add(user);
					}
				}				
			}
		}
		
		DetachedCriteria superficialCriteria = DetachedCriteria.forClass(SuperficialRolesMapping.class);
		superficialCriteria.add(Restrictions.eq("ldId", documentObject.getDocLocId()));
		superficialCriteria.add(Restrictions.eq("cdId", documentObject.getDocCompanyId()));
		List<SuperficialRolesMapping> superficialUsersList = commonDAO.loadAllByCriteria(superficialCriteria);
		
		//adding superficial users to the 'usersList'
		if(null != superficialUsersList){
			for (SuperficialRolesMapping superficialUser : superficialUsersList) {
				usersList.add(superficialUser.getUserId());
			}
		}
		
		//getting the userdetailsDTO objects according to the user IDs and adding to a list
		for(String userId : usersList){
			userDetailsDTOs.add(ApplicationMaps.USERID_USER_MAP.get(userId));
		}
		
		Map<String, String> userMap = new HashMap<String, String>();
		List<UserActivityGroup> activityGroups = null;
		try {
			activityGroups = documentDAO.getUserDocumentActivity(docId);
			if(null != activityGroups && ApplicationConstants.ALL_INT.intValue() == activityGroups.size()){
				mapDefaultUsers(docId);		//map default users as CC,CCC,Sub Owner, Owner
			}
			//getting list of user activity mapping according to docId
//			activityGroups = documentDAO.getUserDocumentActivity(docId);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		
		Map<String,String> userPrintGroupMap = new HashMap<String, String>();
		Map<String,String> userViewGroupMap = new HashMap<String, String>();
		
		//putting superficial users (Owner and CCC) into printGroupMap
		if(null != superficialUsers){
			for(UserDetailsDTO user : superficialUsers){
//				userPrintGroupMap.put(user.getUsername(), user.getUsername());   //commented on 5 Dec 2012
				userPrintGroupMap.put(user.getUsername(), ApplicationMaps.USERID_USERNAME_MAP.get(user.getUsername()));
			}
		}
		
		//putting users having print right in printgroupmap and having view rights in viewgroupmap in table user-activity-group-mapping 
		for(UserActivityGroup activityGroup:activityGroups)
		{
			if(activityGroup.getActivityType().equals(DocActivityType.Print)){
				userPrintGroupMap.put(activityGroup.getUsername(), ApplicationMaps.USERID_USERNAME_MAP.get(activityGroup.getUsername()));
			}
			else{
				userViewGroupMap.put(activityGroup.getUsername(), ApplicationMaps.USERID_USERNAME_MAP.get(activityGroup.getUsername()));
			}
		}
		
		for (UserDetailsDTO userDetailsDTO : userDetailsDTOs)
		{
			for(String printMappedUsers : userPrintGroupMap.keySet()){
				userMap.put(printMappedUsers, userPrintGroupMap.get(printMappedUsers));
			}
			for(String viewMappedUsers : userViewGroupMap.keySet()){
				userMap.put(viewMappedUsers, userViewGroupMap.get(viewMappedUsers));
			}
			
			userMap.put(userDetailsDTO.getUsername(), userDetailsDTO.getUserDisplayName());
		}
		logger.debug("view map: " + userViewGroupMap);
		logger.debug("print map: " + userPrintGroupMap);
		
		UserActivityForm userActivityForm = new UserActivityForm();
		userActivityForm.setDocId(docId);
		userActivityForm.setViewGroup(userViewGroupMap.keySet().toArray(new String[]{}));
		userActivityForm.setPrintGroup(userPrintGroupMap.keySet().toArray(new String[]{}));
		
		requestContext.getFlowScope().put("docId", docId);
		requestContext.getFlowScope().put("viewMap", userViewGroupMap);
		requestContext.getFlowScope().put("printMap", userPrintGroupMap);
		requestContext.getFlowScope().put("userMap", userMap);
		requestContext.getFlowScope().put("userActivityForm", userActivityForm);
		requestContext.getViewScope().put("userActivityForm", userActivityForm);
	}
	
	public void mapDefaultUsers(long docId){
		//mapping default users which are having superficial role for the location and company of the document
		logger.debug("inside method(mapDefaultUsers): for document with docId: " + docId);

		//getting docLocId and docCompanyId from doc general details on basis of docId
		List<Object[]> doc = commonDAO.getDocgeneraldetails(docId);
		List<UserActivityGroup> userActivityToAdd = new ArrayList<UserActivityGroup>();
		
		if(null != doc && doc.size() > ApplicationConstants.ALL_INT.intValue()){
			//getting superficial role mapping objects list on basis of location and company of document
			DetachedCriteria superficialCriteria = DetachedCriteria.forClass(SuperficialRolesMapping.class);
			superficialCriteria.add(Restrictions.eq("ldId", doc.get(0)[0]));
			superficialCriteria.add(Restrictions.eq("cdId", doc.get(0)[1]));
			
			List<SuperficialRolesMapping> superficialList = commonDAO.loadAllByCriteria(superficialCriteria);
			//adding objects to a set to remove duplicacy
			Set<String> tempSet = new HashSet<String>();
			for(SuperficialRolesMapping superficialEntry : superficialList){
				tempSet.add(superficialEntry.getUserId());
				/*if(ApplicationConstants.ALL_INT.intValue() == tempSet.size()) {
					tempSet.add(superficialEntry);
				}
				else{
					for (SuperficialRolesMapping superficialRolesMapping : tempSet) {
						if(superficialRolesMapping.getUserId().equals(superficialEntry.getUserId()))
							continue;
						else
							tempSet.add(superficialEntry);
					}
				}*/
			}
			
			//adding those users who are in superficial set having default as print rights
			for (String username : tempSet) {
				UserActivityGroup userActivityGroup = new UserActivityGroup();
				userActivityGroup.setActivityType(DocActivityType.Print);
				userActivityGroup.setdocId(docId);
				userActivityGroup.setUsername(username);
				userActivityToAdd.add(userActivityGroup);
			}
			logger.debug("+++++++++++++++++++" + userActivityToAdd.size());
			try {
				documentDAO.saveUserActivity(userActivityToAdd);
			} catch (Exception e) {
				logger.debug(e.getMessage(),e);
			}
		}	
	}
	
	
	public void mapUserActivity(UserActivityForm activityForm,RequestContext requestContext){
		logger.debug("inside Method(MapUserActivity): for document with docId: " + activityForm.getDocId()); 
		
		Long docId = activityForm.getDocId();
		String[] oldPrintGroup = requestContext.getRequestParameters().getArray("oldPrintGroup");
		String[] oldViewGroup = requestContext.getRequestParameters().getArray("oldViewGroup");
		HashMap<String, List<UserActivityGroup>> activityGroups = ApplicationUtilities.getUserActivityMapping(activityForm,oldPrintGroup,oldViewGroup);
		List<UserActivityGroup> userActivityToAdd = activityGroups.get("add");
		List<UserActivityGroup> userActivityToDelete = activityGroups.get("delete");
		

		
		//giving print rights to owner and CCC of group company
		
		DetachedCriteria docGeneralCriteria = DetachedCriteria.forClass(DocGeneralDetailsDTO.class);
		docGeneralCriteria.add(Restrictions.eq("docId", docId));
		List<DocGeneralDetailsDTO> documentGeneralList = commonDAO.loadAllByCriteria(docGeneralCriteria);
		
		DocGeneralDetailsDTO documentObject = documentGeneralList.get(0);	
		List<UserDetailsDTO> userList = null;
		Set<UserDetailsDTO> superficialUsers = new HashSet<UserDetailsDTO>();
		CompanyDetailsDTO companyDetailsDTO = ApplicationMaps.COMPANYID_COMPANY_MAP.get(documentObject.getDocCompanyId());
		if(ApplicationConstants.SUBSIDIARY_COMPANY.equalsIgnoreCase(companyDetailsDTO.getCompanyType())) {
			int parentCompanyId = companyDetailsDTO.getParentId();
			DetachedCriteria userCompanyCriteria = DetachedCriteria.forClass(UserDetailsDTO.class);
			userCompanyCriteria.add(Restrictions.eq("cdId", parentCompanyId));
			userList = commonDAO.loadAllByCriteria(userCompanyCriteria);
		}
		//fetching a set of superficial users for the company of document only having role Owner and CCC
		if(null != userList){
			for (UserDetailsDTO user : userList) {
				Collection<GrantedAuthority> rolesList = user.getAuthorities();
				for (GrantedAuthority grantedAuthority : rolesList) {
					RoleDetailsDTO roleDetailsDTO = (RoleDetailsDTO) grantedAuthority;
					if(roleDetailsDTO.getRoleId().equalsIgnoreCase(ApplicationConstants.ROLE_OWNER)
							|| roleDetailsDTO.getRoleId().equalsIgnoreCase(ApplicationConstants.ROLE_CHIEF_CENTRAL_CONTROLLER)){
						superficialUsers.add(user);
					}
				}				
			}
		}
	
		
		for(UserDetailsDTO superficialUserDetails : superficialUsers){
			UserActivityGroup userActivityGroup = new UserActivityGroup();
			userActivityGroup.setdocId(docId);
			userActivityGroup.setUsername(superficialUserDetails.getUsername());
			userActivityGroup.setActivityType(DocActivityType.Print);
			userActivityToAdd.add(userActivityGroup);
		}
	
		/********/
		
		if(userActivityToDelete.size()!=0 || userActivityToDelete!=null)
			for (UserActivityGroup userActivityGroup : userActivityToDelete) {
				System.out.println("DELETE: " + userActivityGroup.getUsername() + "  ::for" + userActivityGroup.getdocId());
			}
			try {
				System.out.println("************ going to delete..." + userActivityToDelete.size());
				
				documentDAO.deleteUserActivity(userActivityToDelete);
			} catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		if(userActivityToAdd.size()!=0 || userActivityToAdd!=null)
			for (UserActivityGroup userActivityGroup : userActivityToAdd) {
				System.out.println("ADD: " + userActivityGroup.getUsername() + "  ::for" + userActivityGroup.getdocId());
			}
			try {
				System.out.println("************ going to save..." + userActivityToAdd.size());
				documentDAO.saveUserActivity(userActivityToAdd);
			} catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		
		requestContext.getFlowScope().put("statusMsg", "Users Map Successfully");
	}

	public void saveAuthSignatory(RequestContext requestContext)
	{
		String[] authSign = requestContext.getRequestParameters().getArray("authId");
		Long docId = requestContext.getRequestParameters().getLong("docId");
		logger.debug("inside method(saveAuthSignatory): for document with docId: " + docId);
		List<String> userList = new ArrayList<String>();
		if(authSign!=null&&authSign.length>0)
			userList.addAll(Arrays.asList(authSign));
		List<DocumentAuthSignatoryDTO> authSignatoryList = new ArrayList<DocumentAuthSignatoryDTO>();
		for(String userId : userList) {
			DocumentAuthSignatoryDTO signatoryDTO = new DocumentAuthSignatoryDTO();
			signatoryDTO.setDocId(docId);
			signatoryDTO.setUserId(userId);
			authSignatoryList.add(signatoryDTO);
		}
		if(authSignatoryList.size()>0) {
			try {
				workflowDao.saveAuthSignatory(authSignatoryList);
			} catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		}
	}

	public void getUsers(RequestContext context)
	{
		String userId = context.getRequestParameters().get("userId");
		String userName = context.getRequestParameters().get("userName");
		String searchEvent = context.getRequestParameters().get("searchEvent");
		UserSearchForm userSearchForm = new UserSearchForm();
		userSearchForm.setUserId(userId);
		userSearchForm.setUserName(userName);
		if(null != searchEvent)
			userSearchForm.setFormAction(searchEvent);
		List<UserDetailsDTO> userDetailsDTOs = (List<UserDetailsDTO>)processDocumentService.searchedUserData(userSearchForm);
		logger.debug("method(getUsers): userdetails for userId: " + userId + " is: " + userDetailsDTOs.toString());
		context.getFlowScope().put("userDetails", userDetailsDTOs);
	}

	public void submitWFRoleDetails(SaveDataInWFTable saveDataInWFTable){
		
		DocReviewerApproverForWFDTO docReviewerApproverForWFDTO = new DocReviewerApproverForWFDTO();
		
		docReviewerApproverForWFDTO.setMasterCode(saveDataInWFTable.getMasterCode());
		docReviewerApproverForWFDTO.setReviewer(saveDataInWFTable.getReviewer());
		docReviewerApproverForWFDTO.setApprover(saveDataInWFTable.getApprover());
		
		try {
			workflowDao.saveWFRoleDetails(docReviewerApproverForWFDTO);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		ApplicationMaps.ARMORY_REVIEVER_APPROVER.put(saveDataInWFTable.getMasterCode(),docReviewerApproverForWFDTO);
	}
	
	private String getMessageForNotificationMail(DocumentWorkflowDetailsDTO workflowDetailsDTO, DocGeneralDetailsDTO docDetailsDTO){
		StringBuilder mailMessage = new StringBuilder();
		
		if(workflowDetailsDTO.getWfEventStatus().equals(WorkflowEventStatus.OPEN)){
			mailMessage.append("<br>Dear " + ApplicationMaps.USERID_USERNAME_MAP.get(workflowDetailsDTO.getWfAssignedUser()) + ",<br><br>");
			mailMessage.append(ApplicationMaps.USERID_USERNAME_MAP.get(ApplicationUtilities.getCurrentUser()));
			
			switch (workflowDetailsDTO.getWfStatus()) {
			case PFR:
				mailMessage.append(" has submitted a document for your review. Please do the needful.<br><br>");
				break;
			case PFRS:
				mailMessage.append(" has rejected a document uploaded by you. Please make required changes and re-submit for review.<br><br>");
				break;
			case PFA:
				mailMessage.append(" has submitted a document for your approval. Please do the needful.<br><br>");
				break;
			case PFRR:
				mailMessage.append(" has rejected a document submitted by you. Please make required changes and re-submit for approval.<br><br>");
				break;
			default:
				break;
			}
		}
		else if(workflowDetailsDTO.getWfStatus().equals(WorkflowStatus.PFA)){
			mailMessage.append("Dear All <br><br> A new document has been added to the system. The document details are as under: <br><br>");
		}
		
		
		mailMessage.append("Document Details:<br><br>");
		mailMessage.append("<table border='1'>");
		mailMessage.append("<tr> <td> Name: &nbsp; </td> <td>" + docDetailsDTO.getDocName() + "</td></tr>");
		if(!ApplicationUtilities.checkIfNullOrBlank(docDetailsDTO.getDocCode())){
			mailMessage.append("<tr> <td> Document Code: &nbsp; </td> <td>" + docDetailsDTO.getDocCode() + "</td></tr>");
		}
		
		mailMessage.append("<tr> <td> Type: &nbsp; </td> <td>" + docDetailsDTO.getDocType() + "</td></tr>");
		mailMessage.append("<tr> <td> Category: &nbsp; </td> <td>" + docDetailsDTO.getDocCategory() + "</td></tr>");
		mailMessage.append("<tr> <td> Sub Category: &nbsp; </td> <td>" + docDetailsDTO.getDocSubCategory() + "</td></tr>");
		mailMessage.append("<tr> <td> Location: &nbsp; </td> <td>" + docDetailsDTO.getDocLocation() + "</td></tr>");
		mailMessage.append("<tr> <td> Department: &nbsp; </td> <td>" + docDetailsDTO.getDocDepartment() + "</td></tr>");
		mailMessage.append("</table><br><br>");
		mailMessage.append("Thanks and Regards<br>DMS Administrator");
		
		return mailMessage.toString();
	}
}

